#pragma once

#include <QBrush>
#include <QGraphicsItem>
#include <QPainterPath>
#include <QFont>

#include "LeGraphics.h"
#include "LeGraphicsPalette.h"
#include "LeGraphicsStyle.h"

class LeGraphicsScene;
class LeGraphicsHandleItem;
class LeGraphicsItemLayer;

class LEGRAPHICSVIEW_EXPORT LeGraphicsItem: public QGraphicsObject
{
    Q_OBJECT
public:
    LeGraphicsItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    virtual ~LeGraphicsItem();

    void setFeatureType(LeGraphicsFeature featureType);
    LeGraphicsFeature featureType() const;
    void setFeatureMetaData(const QMap<QString, QString> &metaData);
    QMap<QString, QString> featureMetaData() const;

    void setStateFlag(LeGraphicsStyle::StateFlag which, bool on = true);
    bool stateFlag(LeGraphicsStyle::StateFlag which) const;
    void setState(LeGraphicsStyle::State state);
    LeGraphicsStyle::State state() const;

    virtual LeGraphicsItem *clone() const = 0;

    LeGraphicsItemLayer *layer() const;

    LeGraphicsScene *graphicsScene() const;

    template<class T>
    T as()
    {
        return qobject_cast<T>(this);
    }

    QList<LeGraphicsHandleItem *> handles() const;

protected:
    template<class T>
    T *createClone() const;
    LeGraphicsHandleItem* addHandle(LeGraphicsHandleRole role);
    LeGraphicsHandleItem* handle(LeGraphicsHandleRole role);
    virtual QPointF handlePositionChangeFilter(LeGraphicsHandleRole role, const QPointF &value);
    void installItemChangeFilter(LeGraphicsItem *filter);
    void removeItemChangeFilter(LeGraphicsItem *filter);
    virtual QVariant itemChangeFilter(LeGraphicsItem *item,
                                      GraphicsItemChange change,
                                      const QVariant &value);

private:
    LeGraphicsFeature m_featureType;
    LeGraphicsStyle::State m_state;
    QMap<QString, QString> m_featureMetaData;
    QMap<LeGraphicsHandleRole, LeGraphicsHandleItem*> m_handleMap;
    QList<LeGraphicsItem*> m_itemChangeFilterItems;

    // QGraphicsItem interface
protected:
    virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
    virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
    virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
};
Q_DECLARE_METATYPE(LeGraphicsItem*)

class LEGRAPHICSVIEW_EXPORT LeGraphicsCompositeItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 1
    };

    LeGraphicsCompositeItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsCompositeItem();

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }
};

class LEGRAPHICSVIEW_EXPORT LeGraphicsCircleItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 2
    };

    LeGraphicsCircleItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsCircleItem();

    void setDiameter(qreal diameter);
    qreal diameter() const;

private:
    qreal m_diameter;
    QRectF m_boundingRect;
    QPainterPath m_shape;

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }

};

class LEGRAPHICSVIEW_EXPORT LeGraphicsRectItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 3
    };

    LeGraphicsRectItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsRectItem();

    void setWidth(qreal width);
    qreal width() const;
    void setHeight(qreal height);
    qreal height() const;

    void setSize(const QSizeF &size);

private:
    QRectF m_rect;
    QPainterPath m_shape;

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }

};
Q_DECLARE_METATYPE(LeGraphicsRectItem*)

class LEGRAPHICSVIEW_EXPORT LeGraphicsFilledPathItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 4
    };

    LeGraphicsFilledPathItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsFilledPathItem();

    void setPath(const QPainterPath &path);
    QPainterPath path() const;

private:
    QPainterPath m_path;
    QRectF m_boundingRect;

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }

};

class LEGRAPHICSVIEW_EXPORT LeGraphicsStrokedPathItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 5
    };

    LeGraphicsStrokedPathItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsStrokedPathItem();

    void setPath(const QPainterPath &path, qreal width);
    qreal strokeWidth();
    QPainterPath path() const;

private:
    qreal m_strokeWidth;
    QPainterPath m_path;
    QPainterPath m_shape;
    QRectF m_boundingRect;

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }

};

class LEGRAPHICSVIEW_EXPORT LeGraphicsLabelItem: public LeGraphicsItem
{
    Q_OBJECT
public:
    enum
    {
        Type = UserType + 6
    };

    LeGraphicsLabelItem(LeGraphicsFeature featureType, QGraphicsObject *parent = nullptr);
    ~LeGraphicsLabelItem();

    void setFont(const QFont &font);
    QFont font() const;

    void setText(const QString &text);
    QString text() const;

private:
    QFont m_font;
    QString m_text;
    QRectF m_boundingRect;
    QPainterPath m_shape;
    void updateGeometry();

    // GraphicsItem interface
public:
    virtual LeGraphicsItem *clone() const override;

    // QGraphicsItem interface
public:
    virtual QRectF boundingRect() const override;
    virtual QPainterPath shape() const override;
    virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
    virtual int type() const override { return Type; }

};
